上篇提到的 Object.defineProperty、Object.defineProperties 為調整物件本身的的屬性特徵方法,這篇將説說 preventExtensions ( 防止擴充 )、seal ( 封裝 )、Freeze ( 凍結 ) 這三種針對物件本身做限制的方法。
preventExtension、seal、freeze 的共同點與差異:preventExtension 可以調整屬性特徵,seal、freeze 不能調整屬性特徵。
seal 屬性特徵中 writable 經測試是可以被調整的,似乎是 seal 有調整過導致,須留意。freeze > seal > preventExtension
特性: 不能「 新增 」物件本身屬性。
結構:Object.preventExtensions(物件)
Others :
Object.preventExtensions(物件) 可搭配 Object.isExtensible(物件) 做驗證看使用了 preventExtensions 後的物件是否可被擴充。
Object.preventExtensions(物件) 可搭 Object.getOwnPropertyDescriptor(物件, '屬性') 查看物件裡的特定屬性特徵。
物件使用 preventExtensions 後的屬性特徵 ( 可使用 Object.getOwnPropertyDescriptor(物件, '物件屬性'); 查詢 )
configurable: true,
enumerable: true,
value: 屬性本身的值
writable: true
preventExtensions 物件屬性特徵不會被改變var person = {
a: 1,
b: 2,
c: {}
}
Object.preventExtensions(person);
console.log(`是否可被擴充 ${Object.isExtensible(person)}`);
console.log(Object.getOwnPropertyDescriptor(person, 'a'));
Object.isExtensible(person) 印出 false,可見 preventExtensions 的物件是不可被擴充的。a 屬性為例,Object.getOwnPropertyDescriptor(person, 'a') 可見 a 屬性的特徵們一樣為預設。
var person = {
a: 1,
b: 2,
c: {}
}
Object.preventExtensions(person);
// 調整屬性
person.a = 'a';
// 新增屬性
person.d = 'd';
// 調整巢狀屬性(新增)
person.c.inC = 'C is Here';
// 調整特徵
Object.defineProperty(person, 'a' , {
configurable: false,
})
delete person.a;
console.log(person);
a 屬性的屬性值調整為 a 是沒問題的。d 屬性後,並沒有在物件中看見新增的 d 屬性,因為 preventExtensions 的用意就是無法新增屬性。preventExtensions 只能對物件本身做限制,無法對物件本身的巢狀屬性做限制,所以在巢狀屬性 c 內再新增 inC 屬性是沒問題的。configurable: false,是沒問題的,可見 preventExtensions 是可以再次調整屬性特徵。物件屬性「無法新增刪除」,也無法重新配置特徵,但是可以調整目前屬性值。
seal 屬性特徵中 writable 經測試是可以被調整的,似乎是 seal 有調整過導致,須留意。seal 與 preventExtensions 是有關聯性的,所以 seal 預設狀態為物件會被加上 preventExtensions,再把 「無法新增刪除,也無法重新配置特徵 」的特性加上。
物件使用 seal 後的屬性特徵為 ( 可使用 Object.getOwnPropertyDescriptor(物件, '物件屬性'); 查詢 )
configurable: false,
enumerable: true,
value: 屬性本身的值
writable: true
Object.seal(物件);
var person = {
a: 1,
b: 2,
c: {}
}
Object.seal(person);
console.log(`是否可被封裝 ${Object.isSealed(person)}`);
// 調整屬性
person.a = 'a';
// 新增屬性
person.d = 'd';
// 調整巢狀屬性(新增)
person.c.inC = 'C is Here'
console.log(person);
a 屬性的屬性值調整為 a 是沒問題的。d 屬性後,並沒有在物件中看見新增的 d 屬性,因為 preventExtensions 的用意就是無法新增屬性。preventExtensions 只能對物件本身做限制,無法對物件本身的巢狀屬性做限制,所以在巢狀屬性 c 內再新增 inC 屬性是沒問題的。
writable 特徵例外var person = {
a: 1,
b: 2,
c: {}
}
Object.seal(person);
console.log(`是否可被封裝 ${Object.isSealed(person)}`);
console.log(Object.getOwnPropertyDescriptor(person, 'a'));
// 調整特徵
Object.defineProperty(person, 'a' , {
writable: false,
})
// Object.defineProperty(person, 'a' , {
// configurable: true,
// })
console.log(Object.getOwnPropertyDescriptor(person, 'a'));
console.log(person);
writable 特徵例外:
修改了物件 a 的屬性特徵 writable 由 true 變 false,並使用 Object.getOwnPropertyDescriptor 查看封裝後物件的屬性特徵,開發者工具依舊顯示 writable: false,驗證**「 seal 封裝後的物件是無法調整屬性特徵 」**。
// 未調整 a 屬性的屬性特徵狀態 ↑

// 調整 a 屬性的 writable 屬性特徵狀態,被覆蓋為 false ↑
調整其他特徵:
Uncaught TypeError。
物件使用 freeze 會讓此物件被凍結並且,
物件使用 freeze 的屬性特徵 ( 可使用 Object.getOwnPropertyDescriptor(物件, '物件屬性'); 查詢 )
configurable: false,
enumerable: true,
value: 屬性本身的值
writable: false
freeze 與 seal 和 preventExtensions 是有關聯性的,所以 freeze 預設狀態為物件會被加上 preventExtensions ( 無法被擴展 ) 和 seal ( 封裝 ) 的特性,也無法被調整值。
Object.freeze(物件);
var person = {
a: 1,
b: 2,
c: {}
}
Object.freeze(person);
console.log(`是否可被擴展 ${Object.isExtensible(person)}`); // false
console.log(`是否可被封裝 ${Object.isSealed(person)}`); // true
console.log(`是否可被凍結 ${Object.isFrozen(person)}`); // true
var person = {
a: 1,
b: 2,
c: {}
}
Object.freeze(person);
// 調整屬性
person.a = 'a';
// 新增屬性
person.d = 'd';
// 調整巢狀屬性(新增)
person.c.inC = 'C is Here'
console.log(person);
freeze 只能針對當下物件凍結,無法對物件屬性的巢狀屬性做凍結。
var person = {
a: 1,
b: 2,
c: {}
}
Object.freeze(person);
// 調整 writable 特徵
Object.defineProperty(person, 'a' , {
writable: true,
})
Uncaught TypeError。configurable、enumerable、value ),一樣會跳出錯誤訊息。